package viz.view.components
{
	import flare.display.DirtySprite;
	import flare.display.TextSprite;
	import flare.query.methods.eq;
	import flare.vis.Visualization;
	import flare.vis.controls.ClickControl;
	import flare.vis.controls.HoverControl;
	import flare.vis.controls.IControl;
	import flare.vis.data.Data;
	import flare.vis.data.EdgeSprite;
	import flare.vis.data.NodeSprite;
	import flare.vis.events.SelectionEvent;
	import flare.vis.events.VisualizationEvent;
	import flare.vis.operator.label.RadialLabeler;
	import flare.vis.operator.layout.BundledEdgeRouter;
	import flare.vis.operator.layout.CircleLayout;
	
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFormat;
	
	import mx.events.FlexEvent;
	import mx.events.ResizeEvent;
	import mx.modules.Module;
	
	
	public class FlareViz extends Module
	{
		private var _vis:Visualization;
		private var _nodeHoverControls:IControl;
		private var _nodeClickControls:IControl;
		private var _edgeHoverControls:IControl;
		private var _edgeClickControls:IControl;
		
		private var _isActive:Boolean;
		private var _interactive:Boolean;
		private var _bounds:Rectangle;
		
		private var _focusNode:NodeSprite;
		
		private var _fmt:TextFormat = new TextFormat("Tahoma", 20);
		
		public function FlareViz():void
		{
			init();
  		}
  		
  		public function get focusNode():NodeSprite{
  			return _focusNode;
  		}
  		
  		private function init():void{
  			addEventListener(ResizeEvent.RESIZE, onResize);
  			addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
  			
  		}
  		
  		private function onResize(event:ResizeEvent=null):void{
			resize( new Rectangle( 10, 10, width - 20, height - 20 ) );
		}
		
		private function onCreationComplete(event:FlexEvent):void{
			removeEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
			//onResize();
		}
	
  		
  		public function flush():void{
  			_isActive = false;
  			removeViz();	
  		}
  		
  		private function removeViz():void{
  			if(_vis && contains(_vis)){
  				rawChildren.removeChild(_vis);
  				//_vis.removeEventListener(VisualizationEvent.UPDATE, onUpdate);
  				_vis = null;
  			}
  		}
  		
  		/* private function onUpdate(event:VisualizationEvent):void{
  			dispatchEvent(event);
  		} */
  		
  		public function set dataProvider( d:Data ):void{
  			_isActive = true;
  			removeViz();
  			visualize( d );
  			interactive  = true;
  		}
  		
  		public function update():void{
  			_vis.update();
  		}
  		
  		public function get interactive():Boolean{
  			return _interactive;
  		}
  		
  		public function set interactive(val:Boolean):void{
  			_interactive = val;
  			if(_interactive){
  				addNodeControls();
  			}else{
  				removeNodeControls();
  			}
  			
  		}
  		
  		public function get isActive():Boolean{
  			return _isActive;
  		}
  		
  		private function visualize(data:Data):void
		{
			initDataProps(data);
			initViz(data);
			addLayout();
			addLabels();
			_vis.update();
			_vis.data.nodes.visit(labelVisitor);// give labels backgrounds for better hitareeas
			rawChildren.addChild(_vis);
			if (_bounds) resize(_bounds);
		}
		
		private function initDataProps( data:Data ):void{
			data.nodes.sortBy("-data.name.length");
			
			data.nodes.setProperties({
				shape: null,                  // no shape, use labels instead
				visible: eq("childDegree",0) // only show leaf nodes			
			});
		}
		
		private function initViz( data:Data ):void{
			_vis = new Visualization(data);
			//_vis.addEventListener(VisualizationEvent.UPDATE, onUpdate);
		}
		
		private function addLabels():void{
			var labeler:RadialLabeler = new RadialLabeler("data.name", true, _fmt, eq("childDegree",0))  // leaf nodes only
			labeler.textMode = TextSprite.EMBED;
			_vis.operators.add(labeler);
			
		}
		
		
		
		private function addLayout():void{
			var layout:CircleLayout = new CircleLayout("depth", null, true),
				router:BundledEdgeRouter = new BundledEdgeRouter(.975);
				//toolTip:TooltipControl = new TooltipControl(EdgeSprite;
			layout.startRadiusFraction = .25;
			
			_vis.operators.add(layout);
			_vis.operators.add(router);
		}
		
		private function addNodeControls():void{
			if(!_nodeHoverControls) _nodeHoverControls = new HoverControl( NodeSprite, HoverControl.DONT_MOVE, onNodeRollover, onNodeRollout );
			if(!_nodeClickControls) _nodeClickControls = new ClickControl( NodeSprite,	1, onNodeClick );	
			_vis.controls.add(_nodeHoverControls);
			_vis.controls.add(_nodeClickControls);
			_vis.data.nodes.setProperties({buttonMode: true});	
		}
		
		
		private function removeNodeControls():void{
			_vis.controls.remove(_nodeHoverControls);
			_vis.controls.remove(_nodeClickControls);
			_vis.data.nodes.setProperties({buttonMode: false});
		}
		
		
		private function labelVisitor(node:NodeSprite):Boolean{
			var tf:TextField;
			if(node.childDegree != 0 ) return false;
			tf = TextSprite(node.props.label).textField
			tf.background = true;
			return false
		}
				
		private function addEdgeControls():void{
			if(!_edgeHoverControls) _edgeHoverControls = new HoverControl( EdgeSprite, HoverControl.DONT_MOVE, onEdgeRollover, onEdgeRollout );
			if(!_edgeClickControls) _edgeClickControls = new ClickControl( EdgeSprite,	1, onEdgeClick );	
			_vis.controls.add(_edgeHoverControls);
			_vis.controls.add(_edgeClickControls);	
			_vis.data.edges.setProperties({buttonMode: true});
		}
		
		private function removeEdgeControls():void{
			_vis.controls.remove(_edgeHoverControls);
			_vis.controls.remove(_edgeClickControls);
			_vis.data.edges.setProperties({buttonMode: false});
		}
		
		private function onNodeClick(evt:SelectionEvent):void{
			dispatchEvent( evt );
		}
		
		private function onEdgeClick(evt:SelectionEvent):void{
			dispatchEvent( evt );
		}

		/** Add highlight to a node and connected edges/nodes */
		private function onNodeRollover(evt:SelectionEvent):void{
			_focusNode = evt.node;
			dispatchEvent(evt);
		}
		
		private function onNodeRollout(evt:SelectionEvent):void{
			_focusNode = null;
			dispatchEvent(evt);
		}
		
		
		private function onEdgeRollover(evt:SelectionEvent):void{
			dispatchEvent(evt);
		}
		
		private function onEdgeRollout(evt:SelectionEvent):void{
			dispatchEvent(evt);
		}
		
		
		public function resize(bounds:Rectangle):void
		{
			_bounds = bounds;
			
			if (_vis) {
				// automatically size labels based on bounds
				var d:Number = Math.min(_bounds.width, _bounds.height);
				_vis.data.nodes.setProperty("props.label.size",
					(d <= 650 ? 10 : d <= 725 ? 11 : 12),
					null, eq("childDegree",0));
				
				// compute the visualization bounds
				_vis.bounds.x = _bounds.x;
				_vis.bounds.y = _bounds.y //+ (0.06 * _bounds.height);
				_vis.bounds.width = _bounds.width;
				_vis.bounds.height = _bounds.height //- (0.05 * _bounds.height);
				// update
				_vis.update();
				
				// layout legend and details
				
			
				// forcibly render to eliminate partial update bug, as
				// the standard RENDER event routing can get delayed.
				// remove this line for faster but unsynchronized resizes
				DirtySprite.renderDirty();
				
				//dispatchEvent(new VisualizationEvent(VisualizationEvent.UPDATE));
			}
		}
		
		// --------------------------------------------------------------------
		
	
		
	} // end of class DependencyGraph
}